package com.ck.express.activity

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.device.ScanManager
import android.media.AudioAttributes
import android.media.SoundPool
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.VibrationEffect
import android.os.Vibrator
import android.util.Log
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.ck.express.R
import com.ck.express.databinding.ActivityScanBinding
import com.ck.express.db.ExpressDatabase
import com.ck.express.db.entity.FailedDeliveryRequest
import com.ck.express.db.entity.FailedLatticeRequest
import com.ck.express.models.DownLatticeRequest
import com.ck.express.models.LogisticsLatticeRequest
import com.ck.express.models.SegmentCodeRequest
import com.ck.express.tcp.TcpClient
import com.ck.express.tcp.TcpOperationDownClient
import com.ck.express.tcp.TcpOperationGirdClient
import com.ck.express.utils.JsonUtil
import com.ck.express.utils.JsonUtil.objectMapper
import com.ck.express.utils.MockDeviceInfoProvider
import com.ck.express.vo.ApiResponse
import com.ck.express.vo.DownLatticeVO
import com.ck.express.vo.LogisticsLatticeVO
import com.ck.express.vo.SegmentCodeVO
import com.fasterxml.jackson.core.type.TypeReference
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.encodeToString
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.TimeZone
import java.util.UUID


class ScanActivity : AppCompatActivity() {

    companion object {
        var instance: ScanActivity? = null
    }

    private lateinit var binding: ActivityScanBinding
    private lateinit var scanManager: ScanManager
    private lateinit var soundPool: SoundPool
    private var beepSoundId: Int = 0

    private var isProcessing = false
    private var lastScanTime: Long = 0
    private val SCAN_THROTTLE_MS = 800

    private val scanReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val action = intent.action
            Log.d("ScanReceiver", "Received action: $action")

            when {
                action.equals(ScanManager.ACTION_DECODE, ignoreCase = true) -> {
                    val barcode = intent.getStringExtra(ScanManager.BARCODE_STRING_TAG)
                    handleHardwareBarcode(barcode)
                }

                action.equals("urovo.rcv.message", ignoreCase = true) -> {
                    handleHardwareBarcode(intent.getStringExtra("data"))
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        instance = this
        binding = ActivityScanBinding.inflate(layoutInflater)
        setContentView(binding.root)

        initViews()
        initSound()
        initScanner()
        registerScannerReceiver()

        callExternalScanner()
    }

    private fun initViews() {
        binding.toolbar.apply {
            setBackgroundColor(ContextCompat.getColor(this@ScanActivity, R.color.primary))
            title = "扫描快递"
            setNavigationOnClickListener { finish() }
        }

        // 手动输入按钮，点击时让输入框获取焦点并弹软键盘
        binding.manualInputButton.setOnClickListener {
            binding.barcodeInputField.requestFocus()
            binding.barcodeInputField.setSelection(binding.barcodeInputField.text.length)
            val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            imm.showSoftInput(binding.barcodeInputField, InputMethodManager.SHOW_IMPLICIT)
        }

        // 确定按钮点击事件：提交输入框内容
        binding.submitBarcodeButton.setOnClickListener {
            val barcode = binding.barcodeInputField.text.toString().trim()
            if (barcode.isNotEmpty()) {
                // 校验条码是否有效
                if (!isValidBarcode(barcode)) {
                    runOnUiThread {
                        binding.statusText.text = "无效条码：${barcode}"
                        Log.w("ScanActivity", "拒绝无效条码：$barcode")
                    }
                    return@setOnClickListener
                }else{
                    processBarcode(barcode)
                }
            } else {
                Toast.makeText(this, "请输入快递单号", Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun initScanner() {
        try {
            scanManager = ScanManager()
            if (!scanManager.scannerState) {
                scanManager.openScanner()
            }
            if (scanManager.outputMode != 0) {
                scanManager.switchOutputMode(0)
            }
            Log.d("Scanner", "Scanner initialized. Mode: Intent")
        } catch (e: Exception) {
            Log.e("Scanner", "Init failed", e)
            Toast.makeText(this, "扫码服务初始化失败，可手动输入", Toast.LENGTH_LONG).show()
//            binding.barcodeInputField.requestFocus()
        }
    }

    private fun registerScannerReceiver() {
        IntentFilter().apply {
            addAction("urovo.rcv.message")
            addAction("android.intent.ACTION_DECODE_DATA")
            priority = Int.MAX_VALUE
        }.also { registerReceiver(scanReceiver, it) }
    }

    private fun callExternalScanner() {
        try {
            val intent = Intent("com.android.scancontext")
            intent.putExtra("scan_type", "barcode")
            intent.putExtra("scan_action", "start")
            sendBroadcast(intent)
        } catch (e: Exception) {
            Log.e("ScanActivity", "外部扫码广播失败: ${e.message}")
        }
    }

    private fun handleHardwareBarcode(barcode: String?) {
        barcode?.let {
            Log.d("HardwareScan", "硬件扫描结果: $it")
            processScannedBarcode(it)
        }
    }

    private fun processScannedBarcode(barcode: String) {

        // 校验条码是否有效
        if (!isValidBarcode(barcode)) {
            runOnUiThread {
                binding.statusText.text = "无效条码：${barcode}"
                Log.w("ScanActivity", "拒绝无效条码：$barcode")
            }
            return
        }

        val currentTime = System.currentTimeMillis()
        if (isProcessing || (currentTime - lastScanTime) < SCAN_THROTTLE_MS) return

        lastScanTime = currentTime
        isProcessing = true

        runOnUiThread {
            soundPool.play(beepSoundId, 1f, 1f, 0, 0, 1f)
            vibrate()
            Log.i("ScanActivity", "扫描成功:$barcode")
            binding.barcodeInputField.setText(barcode)
            binding.barcodeInputField.setSelection(barcode.length)
            binding.statusText.text = "扫描成功"

            // 隐藏软键盘
            val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            imm.hideSoftInputFromWindow(binding.barcodeInputField.windowToken, 0)

            processBarcode(barcode)
        }
    }

    /**
     * 校验条码规则：
     * 1. 首字母必须是 D/R/G（不区分大小写） 或 前两字母是 YT
     * 2. 长度必须 > 15
     */
    private fun isValidBarcode(barcode: String): Boolean {
        // 长度校验（先做快速失败检查）
        if (barcode.length < 15) {
            Log.w("ScanActivity", "条码长度不足：${barcode.length}")
            return false
        }

        val normalized = barcode.uppercase()
        return when (normalized.first()) {
            // 情况1：单字母前缀 (D/R/G)
            'D', 'R', 'G' -> true
            // 情况2：需要检查双字母前缀 (YT)
            'Y' -> normalized.startsWith("YT")
            // 其他情况一律无效
            else -> false
        }.also { result ->
            if (!result) Log.w("ScanActivity", "无效条码格式：$barcode")
        }
    }

    private fun processBarcode(barcode: String) {
        getSegmentCode(barcode) { segmentData ->
            if (segmentData != null) {
                if (!segmentData.daTouBi.isNullOrEmpty()) {
                    runOnUiThread {
                        binding.statusText.text = "获取三段码成功"
                    }
                    callDeliveryApi(barcode, segmentData) { success ->
                        if (success) {
                            runOnUiThread {
                                binding.statusText.text = "供件成功"
                            }
                            Handler(Looper.getMainLooper()).postDelayed({
                                callGridDropApi(barcode, segmentData) {
                                    runOnUiThread {
                                        binding.statusText.text = "落格成功"
                                    }
                                    isProcessing = false
                                }
                            }, 3000)
                        } else {
                            isProcessing = false
                            runOnUiThread {
                                binding.statusText.text = "供件失败"
                                Toast.makeText(this@ScanActivity, "供件失败", Toast.LENGTH_SHORT)
                                    .show()
                            }
                        }
                    }
                } else {
                    isProcessing = false
                    runOnUiThread {
                        binding.statusText.text = "未获取三段码"
                        Toast.makeText(this@ScanActivity, "异常：未获取三段码", Toast.LENGTH_SHORT)
                            .show()
                    }
                }
            } else {
                isProcessing = false
                runOnUiThread {
                    binding.statusText.text = "获取三段码失败"
                    Toast.makeText(this@ScanActivity, "获取三段码失败", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    private fun getSegmentCode(barcode: String, callback: (SegmentCodeVO?) -> Unit) {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val chinaTimeFormatter = SimpleDateFormat(
                    "yyyy-MM-dd HH:mm:ss.SSS",
                    Locale.getDefault()
                ).apply {
                    timeZone = TimeZone.getTimeZone("Asia/Shanghai") // 显式设置中国时区
                }
                val currentTime = chinaTimeFormatter.format(Date())
                val request = SegmentCodeRequest(
                    signature = LogisticsApp.userSession.getSignature(),
                    createTime = currentTime,
                    waybillNo = barcode,
                    txId = UUID.randomUUID().toString().replace("-", ""),
                    schemeId = LogisticsApp.userSession.getGridSchemeId()
                )

                val jsonBody = JsonUtil.json.encodeToString(request)
                val responseJson = TcpClient.send(jsonBody)

                Log.i("三段码返回", "$responseJson")

                val response: ApiResponse<SegmentCodeVO> = JsonUtil.objectMapper.readValue(
                    responseJson,
                    object : TypeReference<ApiResponse<SegmentCodeVO>>() {}
                )

                val segmentResponse = response.data

                withContext(Dispatchers.Main) {
                    binding.segmentCodeText.text = "三段码: ${segmentResponse?.daTouBi ?: "无"}"
                    callback(segmentResponse)
                }
            } catch (e: Exception) {
                Log.e("getSegmentCode", e.message ?: "错误")
                withContext(Dispatchers.Main) {
                    Toast.makeText(this@ScanActivity, "请求三段码失败", Toast.LENGTH_SHORT).show()
                    callback(null)
                }
            }
        }
    }

    private fun callDeliveryApi(
        barcode: String,
        segmentData: SegmentCodeVO?,
        callback: (Boolean) -> Unit
    ) {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                Log.i("投递接口", "开始调用投递接口，快递单号: $barcode")
                if (segmentData == null) {
                    Toast.makeText(this@ScanActivity, "获取三段码异常", Toast.LENGTH_SHORT).show()
                    callback(false)
                    return@launch
                }
                // 1. 优化时间格式化（强制使用中国时区 UTC+8）
                val chinaTimeFormatter = SimpleDateFormat(
                    "yyyy-MM-dd HH:mm:ss.SSS",
                    Locale.getDefault()
                ).apply {
                    timeZone = TimeZone.getTimeZone("Asia/Shanghai") // 显式设置中国时区
                }
                val currentTime = chinaTimeFormatter.format(Date())
                val request = LogisticsLatticeRequest(
                    signature = LogisticsApp.userSession.getSignature(),
                    createTime = currentTime,
                    waybillNo = barcode,
                    txId = UUID.randomUUID().toString().replace("-", ""),
                    schemeId = LogisticsApp.userSession.getGridSchemeId(),
                    createUserCode = LogisticsApp.userSession.getUserCode(),
                    autoDeviceNo = "1",
                    latticeNo = segmentData.latticeNo,
                    mac = MockDeviceInfoProvider.getMockMacAddress(),
                    destOrgCode = segmentData.destOrgCode,
                    latticeOrgCode = segmentData.latticeOrgCode,
                    latticeThreeCode = segmentData.extend1,
                    daTouBi = segmentData.daTouBi,
                    empCode = segmentData.empCode,
                    containerNo = "CQ88888888"

                )
                val jsonBody = JsonUtil.json.encodeToString(request)
                val responseJson = TcpOperationDownClient.send(jsonBody)
                Log.i("供格返回", responseJson)
                val response: ApiResponse<LogisticsLatticeVO> = objectMapper.readValue(
                    responseJson,
                    object : TypeReference<ApiResponse<LogisticsLatticeVO>>() {}
                )

                withContext(Dispatchers.Main) {
                    if (response.isSuccess()) {
                        Toast.makeText(this@ScanActivity, "投递成功", Toast.LENGTH_SHORT).show()
                        callback(true)
                    } else {
                        Toast.makeText(
                            this@ScanActivity,
                            "投递失败: ${response.msg}",
                            Toast.LENGTH_SHORT
                        ).show()
                        callback(false)
                        saveFailedDeliveryRequest(request, response.msg)
                    }
                }
            } catch (e: Exception) {
                Log.e("callDeliveryApi", e.message ?: "错误")
                withContext(Dispatchers.Main) {
                    Toast.makeText(this@ScanActivity, "投递失败", Toast.LENGTH_SHORT).show()
                    callback(false)
                }
            }
        }
    }

    private suspend fun saveFailedDeliveryRequest(
        request: LogisticsLatticeRequest,
        failureReason: String?
    ) {
        val db = ExpressDatabase.getInstance(this)
        val failedRequest = FailedDeliveryRequest(
            waybillNo = request.waybillNo ?: "",
            signature = request.signature,
            createTime = request.createTime,
            txId = request.txId ?: "",
            schemeId = request.schemeId,
            createUserCode = request.createUserCode,
            autoDeviceNo = request.autoDeviceNo,
            latticeNo = request.latticeNo ?: "",
            mac = request.mac ?: "",
            destOrgCode = request.destOrgCode ?: "",
            latticeOrgCode = request.latticeOrgCode ?: "",
            latticeThreeCode = request.latticeThreeCode ?: "",
            daTouBi = request.daTouBi ?: "",
            empCode = request.empCode ?: "",
            failureReason = failureReason ?: ""
        )
        db.failedDeliveryRequestDao().insert(failedRequest)
    }

    private fun callGridDropApi(
        barcode: String,
        segmentData: SegmentCodeVO?,
        callback: () -> Unit
    ) {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                Log.i("落格接口", "开始调用落格接口，快递单号: $barcode")
                // 1. 优化时间格式化（强制使用中国时区 UTC+8）
                val chinaTimeFormatter = SimpleDateFormat(
                    "yyyy-MM-dd HH:mm:ss.SSS",
                    Locale.getDefault()
                ).apply {
                    timeZone = TimeZone.getTimeZone("Asia/Shanghai") // 显式设置中国时区
                }
                val currentTime = chinaTimeFormatter.format(Date())
                val dropRequest = segmentData?.let {
                    DownLatticeRequest(
                        signature = LogisticsApp.userSession.getSignature(),
                        createTime = currentTime,
                        waybillNo = barcode,
                        txId = UUID.randomUUID().toString().replace("-", ""),
                        autoDeviceNo = "1",
                        createUserCode = LogisticsApp.userSession.getUserCode(),
                        schemeId = LogisticsApp.userSession.getGridSchemeId(),
                        latticeNo = segmentData.latticeNo,
                        cartNo = "1-10",
                        latticeThreeCode = it.extend1,
                        daTouBi = segmentData.daTouBi,
                        extend2 = segmentData.extend2
                    )
                }
                val jsonBody = JsonUtil.json.encodeToString(dropRequest)
                val responseJson = TcpOperationGirdClient.send(jsonBody)
                Log.i("落格返回", responseJson)
                val response: ApiResponse<DownLatticeVO> = objectMapper.readValue(
                    responseJson,
                    object : TypeReference<ApiResponse<DownLatticeVO>>() {}
                )
                withContext(Dispatchers.Main) {
                    if (response.isSuccess()) {
                        Toast.makeText(this@ScanActivity, "落格成功", Toast.LENGTH_SHORT).show()
                    } else {
                        saveFailedLatticeRequest(dropRequest!!, response.msg)
                        Toast.makeText(this@ScanActivity, "落格失败", Toast.LENGTH_SHORT).show()
                    }
                    callback()
                }
            } catch (e: Exception) {
                Log.e("callGridDropApi", e.message ?: "错误")
                withContext(Dispatchers.Main) {
                    Toast.makeText(this@ScanActivity, "落格失败", Toast.LENGTH_SHORT).show()
                    callback()
                }
            }
        }
    }

    private suspend fun saveFailedLatticeRequest(
        request: DownLatticeRequest,
        failureReason: String?
    ) {
        val db = ExpressDatabase.getInstance(this)
        val failedRequest = FailedLatticeRequest(
            waybillNo = request.waybillNo ?: "",
            signature = request.signature,
            createTime = request.createTime,
            txId = request.txId ?: "",
            schemeId = request.schemeId,
            createUserCode = request.createUserCode,
            autoDeviceNo = request.autoDeviceNo,
            latticeNo = request.latticeNo ?: "",
            latticeThreeCode = request.latticeThreeCode ?: "",
            daTouBi = request.daTouBi ?: "",
            failureReason = failureReason ?: "",
            mac = request.mac ?: "",
            destOrgCode = request.destOrgCode ?: "",
            latticeOrgCode = request.latticeOrgCode ?: ""
        )
        db.failedLatticeRequestDao().insert(failedRequest)
    }

    private fun initSound() {
        val audioAttributes = AudioAttributes.Builder()
            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
            .build()

        soundPool = SoundPool.Builder()
            .setMaxStreams(1)
            .setAudioAttributes(audioAttributes)
            .build()

        beepSoundId = soundPool.load(this, R.raw.beep, 1)
    }

    private fun vibrate() {
        val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            vibrator.vibrate(VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE))
        } else {
            vibrator.vibrate(100)
        }
    }



    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(scanReceiver)
        soundPool.release()

    }


}
